package Ioc_DI;

import jakarta.annotation.Resource;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;

/**
 * 依赖注入
 * 注解@Autowired在同一个类中存在多个bean对象的话就会出问题
 * 因为spring发现有俩个相同返回类型的返回，就不知道要放回那个了
 * 那么就需要指定那个为默认的 spring提过了三种解决方案
 * 有@Primary @Qualifier @Resource
 * 在 @Autowired和@Resource的区别
 * 1.Autowired是按类的类型来注入对象，而Resource是按名称来注入
 * Resource支持更多的设置，比如根据名称来获取bean，还能作为参数
 * 注解@Autowaired的装配顺序
 * 先是按类型找到对应的bean没找到，抛出异常，找到了，如果是一个，自动装配，多个看是否有qualifier
 * 没有就抛出异常，有就按qualifier设置的名称查找，找到了自动装配，没找到，抛出异常，若没有qualifier，按名称查找，若没有抛出异常
 * 有就自动转配
 */
@Data
@Component
class multipleBean {
    public String str;

    //1 primary
    @Primary
    @Bean("b1")
    private multipleBean b1() {
        multipleBean m = new multipleBean();
        m.str = "hello1";
        return m;
    }

    @Bean("b2")
    private multipleBean b2() {
        multipleBean m = new multipleBean();
        m.str = "hello2";
        return m;
    }

    @Bean("b3")
    private helloDi helloDi1() {
        helloDi helloDi = new helloDi();
        return helloDi;
    }

    @Bean("b4")
    private String b4() {
        return "hello4";
    }
}
@Component
class getMu{
    //如何设置默认bean对象
    //2 qualifier 在注入的时候默认为名字b1的bean
    @Qualifier("b1")
    @Autowired
    private multipleBean b3;

    //3 Resource 在注入的时候是按名字来注入的
    @Resource(name = "b2")
    private multipleBean b4;

    private multipleBean b5;
    private multipleBean b6;

    //这样也行
    @Autowired
    public void getB3_4(@Qualifier("b1") multipleBean b5, @Qualifier("b2") multipleBean b6) {
        this.b5 = b5;
        this.b6 = b6;
    }

    void retB5_6() {
        System.out.println(b5);
        System.out.println(b6);
    }
}

@Component
public class injectionLabel {
    //属性注入
    @Autowired
    helloDi helloDi;

    helloDi2 helloDi2;

    //通过构造方法来注入
    injectionLabel(helloDi2 h) {
        helloDi2 = h;
        helloDi = null;
    }

    helloDi3 helloDi3;

    //使用setter来注入,也就是通过方法来注入对象
    @Autowired
    public void setHelloDi3(helloDi3 h) {
        helloDi3 = h;
    }


    public void p() {
        System.out.println("属性注入");
        helloDi.p();
        helloDi2.p();
        helloDi3.p();
    }
}

@Component
class helloDi{
    public void p() {
        System.out.println("helloDi");
    }
}


@Component
class helloDi2{
    public void p() {
        System.out.println("helloDi2");
    }
}

@Component
class helloDi3{
    public void p() {
        System.out.println("helloDi3");
    }
}

//Resource 类型加名字 发现类型不同的话就会包注入依赖失败异常
@Component
class r1 {
    public void p() {
        System.out.println("r1");
    }
}

@Component
class r2 {
    public void p() {
        System.out.println("r2");
    }
}

@Component
class get{
    @Resource(name = "r2")
    private r2 rr2(r2 r){
        return r;
    }

    @Resource(name = "r1")
    private r1 rr1(r1 r){
        return r;
    }
}














